#include <QtSql/QSqlDatabase>
#include <QtSql/QSqlQuery>
#include <QPair>

#include "meta_center_server.h"
#include "format_packet.h"
#include "logger.h"

MetaCenterServer::MetaCenterServer(QObject *parent, int port)
    :QTcpServer(parent)
{
    if(true == this->listen(QHostAddress::Any, port))
    {
        MYLOG("listen port %d", port);
    }
    else
    {
        MYLOG("listen port %d error", port);
        return;
    }

    connect(this, SIGNAL(newConnection()), this, SLOT(acceptFileConnection()));
}

MetaCenterServer::~MetaCenterServer()
{
    for(int i = 0; i < peer_node_socket_list.count(); ++i)
    {
        delete peer_node_socket_list.at(i).first;
    }
}


QTcpSocket* MetaCenterServer::find_socket(QString username)
{
    int i = 0;
    for(i = 0; i < peer_node_socket_list.count(); ++i)
    {
        if(peer_node_socket_list.at(i).second == username)
        {
            return peer_node_socket_list.at(i).first;
        }
    }
    return NULL;
}

void MetaCenterServer::UpdatePeerNodes(QString msg, int length)
{
    emit UpdateMetaCenterServer(msg, length, UpdateMsg);
    // 更新界面,
    for(int i = 0; i < peer_node_socket_list.count(); ++i)
    {
        QTcpSocket *item = peer_node_socket_list.at(i).first;
        format_packet fmsg(msg, OTHERKIND);
        if(item->write(fmsg.fmpak.toLatin1(),length + 8) != length)
        {
            //将消息广播给所有人
            continue;
        }
    }
}

void MetaCenterServer::slotDisconnected(int descriptor)
{
    int i = 0;
    for(i = 0; i < peer_node_socket_list.count(); ++i)
    {
        QTcpSocket *item = peer_node_socket_list.at(i).first;
        if(item->socketDescriptor() == descriptor)
        {
            if(peer_node_socket_list.at(i).second != "Unknown")
                emit UpdateMetaCenterServer("", i, RemoveName);
            peer_node_socket_list.removeAt(i);
            break;
        }
    }
}

void MetaCenterServer::UpdateUserNameHandle(QString msg)
{
    int i = 0;
    int pos = i;
    while(msg.at(i++) != ';');

    QString username = msg.mid(pos, i - 1);
    pos = i;
    while(msg.at(i++) != ';');

    QString password = msg.mid(pos, i - pos - 1);
    QSqlQuery query(db);
    QTcpSocket *item = peer_node_socket_list.last().first;

    query.exec("select * from login where Username='" + username + "'");
    if(!query.next())
    {
        msg = "Server: login error, unknown user name.";
        MYLOG("peernode: login error, unknown username:%s", username.toStdString().c_str());
        format_packet fmsg(msg, ERRDCKIND);
        item->write(fmsg.fmpak.toLatin1(),fmsg.fmpak.length());
    }
    else
    {
        if(query.value(2).toString() != password)
        {
            msg = "Server: login error, password is wrong.";
            MYLOG("peernode: login error, password is wrong:%s", password.toStdString().c_str());
            format_packet fmsg(msg, ERRDCKIND);
            item->write(fmsg.fmpak.toLatin1(),fmsg.fmpak.length());
        }
        else
        {
            MYLOG("peernode: login success! user:%s password:%s", username.toStdString().c_str(), password.toStdString().c_str());
            peer_node_socket_list.last().second = username;
            emit UpdateMetaCenterServer(username, username.length(), UpdateName);
        }
    }
}


void MetaCenterServer::UpdateUserInfoHandle(QString msg)
{
    int i = 0;
    int pos = i;
    while(msg.at(i++) != ';');
    QString username = msg.mid(pos, i - 1);
    pos = i;
    while(msg.at(i++) != ';');
    QString password = msg.mid(pos, i - pos - 1);
    MYLOG("peernode signUp/signOut, username = %s, password = %s", username.toStdString().c_str(), password.toStdString().c_str());

    QSqlQuery query(db);
    QTcpSocket *item = peer_node_socket_list.last().first;

    // 数据库中只判断 username,
    query.exec("select * from login where Username='" + username + "'");
    if(query.next())
    {
        msg = "Server: sign error, user name exists.";
        format_packet fmsg(msg, SIGNFAILKIND);
        item->write(fmsg.fmpak.toLatin1(),fmsg.fmpak.length());
    }
    else
    {
        if(!query.exec("insert into login (Username, Password) values( '" + username + "', '" + password + "')"))
        {
            msg = "Server: sign error";
            format_packet fmsg(msg, SIGNFAILKIND);
            item->write(fmsg.fmpak.toLatin1(),fmsg.fmpak.length());
        }
        else
        {
            msg = "Server: sign success";
            format_packet fmsg(msg, SIGNSCKIND);
            item->write(fmsg.fmpak.toLatin1(),fmsg.fmpak.length());
            MYLOG("Server: sign success, username = %s, password = %s", username.toStdString().c_str(), password.toStdString().c_str())
        }
    }
}

// 这里只是更新, 并没有 response,
void MetaCenterServer::UpdateMetaHandle(QString mt)
{
    MYLOG("perrnode login, send NAMEMSG:%s",mt.toStdString().c_str());
    QSqlQuery query(db);
    tcp_meta mt_t(mt);
    QString query_str = "insert into Resource(Filename,Size,Filepath,Owner,IP,Port) values( ";

    query_str = query_str + "'" + mt_t.filename + "', ";
    query_str = query_str + QString::number(mt_t.size) + ", ";
    query_str = query_str + "'" + mt_t.filepath + "', ";
    query_str = query_str + "'" + mt_t.owner + "', ";
    query_str = query_str + "'" + mt_t.ip + "', ";
    query_str = query_str + QString::number(mt_t.port) + ")";
    query.exec(query_str);
}

void MetaCenterServer::ReturnMetaHandle(QString username)
{
    MYLOG("peernode login, username = %s", username.toStdString().c_str());
    bool flag = false;
    QSqlQuery query(db);
    QTcpSocket *item = find_socket(username);
    if(item == NULL)
    {
        return;
    }

    query.exec("select * from Resource where Owner='" + username + "'");
    while(query.next())
    {
        tcp_meta mt;
        mt.filename = query.value(1).toString();
        mt.size = query.value(2).toString().toLong();
        mt.filepath = query.value(3).toString();
        mt.owner = query.value(4).toString();
        mt.ip = query.value(5).toString();
        mt.port = query.value(6).toString().toLong();
        QString msg = mt.toString();
        format_packet fmsg(msg, RESKIND);
        while(item->write(fmsg.fmpak.toLatin1(),msg.length() + 8) != msg.length() + 8);
        flag = true;
    }
    if(flag == false)
    {
        QString msg = "";
        format_packet fmsg(msg, RESKIND);
        while(item->write(fmsg.fmpak.toLatin1(),msg.length() + 8) != msg.length() + 8);
    }
}

void MetaCenterServer::DeleteMeta(QString msg)
{
    int i = 0;
    int pos = i;
    QSqlQuery query(db);

    while(msg.at(i++) != ';');
    QString username = msg.mid(pos, i - 1);
    qDebug() << msg;
    for(pos = i; i < msg.length(); ++i)
    {
        if(msg.at(i) == ';')
        {
            QString filename = msg.mid(pos, i - pos);
            query.exec("delete from Resource where FileName='" + filename
                       + "' AND Owner='" + username + "'");
            pos = i + 1;
        }
    }
}

void MetaCenterServer::SearchMeta(QString msg)
{
    // search share file message,

    int i = 0;
    int pos = i;
    while(msg.at(i++) != ';');
    QString username = msg.mid(pos, i - 1);
    pos = i;
    while(msg.at(i++) != ';');
    QString filename = msg.mid(pos, i - pos - 1);

    bool flag = false;
    QSqlQuery query(db);
    QTcpSocket *item = find_socket(username);
    if(item == NULL)
    {
        return;
    }

    /// 严格匹配：如果希望模糊匹配
    /////query.exec("select * from Resource where FileName='" + filename + "'");

    ///如果希望模糊匹配
    QString sqlStr = "select * from Resource where FileName like '%"+ filename +"%'" + ";";
    query.exec(sqlStr);
    while(query.next())
    {
        tcp_meta mt;
        mt.filename = query.value(1).toString();
        mt.size = query.value(2).toString().toLong();
        mt.filepath = query.value(3).toString();
        mt.owner = query.value(4).toString();
        mt.ip = query.value(5).toString();
        mt.port = query.value(6).toString().toLong();
        if(find_socket(mt.owner) != NULL)
        {
            mt.online = "on";
        }
        else
        {
            mt.online = "off";
        }
        QString msg = mt.toString();
        format_packet fmsg(msg, SRHKIND);
        MYLOG("msg = %s", msg.toStdString().c_str());
        while(item->write(fmsg.fmpak.toLatin1(),msg.length() + 8) != msg.length() + 8);
        flag = true;
    }
    if(flag == false)
    {
        QString msg = "";
        format_packet fmsg(msg, SRHKIND);
        while(item->write(fmsg.fmpak.toLatin1(),msg.length() + 8) != msg.length() + 8);
    }
}


void MetaCenterServer::acceptFileConnection()
{
    QTcpSocket *client = this->nextPendingConnection();
    qintptr sockfd = client->socketDescriptor();
    qDebug() << sockfd;
    incomingConnection(sockfd);
}

///接受　新的客户端连接
void MetaCenterServer::incomingConnection(int socketDescriptor)
{
    /// 客户端发送的所有消息，都通过 信号槽 进行统一管理
    PeerNodeConnSocket *peer_node_socket = new PeerNodeConnSocket(this);
    connect(peer_node_socket,SIGNAL(UpdateClients(QString,int)),this,SLOT(UpdatePeerNodes(QString,int)));
    connect(peer_node_socket,SIGNAL(Disconnected(int)),this,SLOT(slotDisconnected(int)));
    connect(peer_node_socket,SIGNAL(UpdateUserName(QString)),this,SLOT(UpdateUserNameHandle(QString)));
    connect(peer_node_socket,SIGNAL(UpdateUserInfo(QString)),this,SLOT(UpdateUserInfoHandle(QString)));
    connect(peer_node_socket,SIGNAL(UpdateMeta(QString)),this,SLOT(UpdateMetaHandle(QString)));
    connect(peer_node_socket,SIGNAL(ReturnMeta(QString)),this,SLOT(ReturnMetaHandle(QString)));
    connect(peer_node_socket,SIGNAL(DeleteMeta(QString)),this,SLOT(DeleteMeta(QString)));
    connect(peer_node_socket,SIGNAL(SearchMeta(QString)),this,SLOT(SearchMeta(QString)));
    peer_node_socket->setSocketDescriptor(socketDescriptor);
    QString name = "Unknown";
    QPair<PeerNodeConnSocket*, QString> pair(peer_node_socket, name);
    peer_node_socket_list.append(pair);
}

